package com.huluobo.lib_base

import android.util.Log
import android.widget.Toast
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ToastUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import java.io.File

/**
 *  Created by LC on 2025/8/18.
 *  数据在ViewModel中流转的过程
 *  1.用户通过UI(View)发起意图,意图会通过管道的发送,保存在管道当中
 *  2.在当前类的初始化的时候,一直在接收管道中的意图
 *  3.接收后会发送给对应的ViewModel,比如登录的ViewModel
 *  4.在对应的ViewModel中需要处理意图,比如登录处理意图,就是去请求网络
 *  5.处理意图产生网络请求,会调用到当前类的请求网络方法,成功或者失败后会调用到对应的状态
 */
abstract class BaseViewModel<uiIntent : UIIntent> : ViewModel() {

    //存放意图的管道(频道),UNLIMITED 代表当前的频道没有最小值
    private val _uiIntent = Channel<UIIntent> { Channel.UNLIMITED }

    //可变的状态,并且将状态转换为一个带状态流,泛型是所有状态的密封类
    private var _state = MutableStateFlow<UIState>(UIState.OnLoading)

    //默认产生的读取的状态
    //由于状态是被private修饰的,所以需要一个对外暴露的方法,避免其他人修改当前的状态
    val state: StateFlow<UIState>
        get() = _state

    //初始化的方法,由于kotlin中没有提供构造方法的位置,所以kotlin提供了一个初始化的位置
    //它触发在一个类new的时候
    init {
        viewModelScope.launch {
            //将所有意图接收,并且存放到管道当中
            _uiIntent.receiveAsFlow().collect {
                handleIntent(it)
            }
        }
    }

    //所有集成当前类(ViewModel),都需要实现该方法,来处理对应的意图
    //比如登录的Intent,需要处理登录的意图,到底是请求网络,还是请求数据库
    abstract fun handleIntent(it: UIIntent)

    //发送意图的方法
    //当页面中需要有请求数据的时候,需要调用该方法来传入一个意图
    fun sendIntent(intent: UIIntent) {
        viewModelScope.launch {
            _uiIntent.send(intent)
        }
    }

    fun httpRequest(request: Flow<Res<Any>>, type: StateType = StateType.DEFAULT) {
        viewModelScope.launch {
            //Dispatchers 调度器
            //将请求的方法转换到子线程中运行
            request.flowOn(Dispatchers.IO)
                //捕获异常
                .catch {
                    ToastUtils.showLong("网络请求错误:${it.message}")
                    Log.e("TagA", "网络请求错误:${it.message}")
                }
                //接收流的内容
                .collect {
                    if (it.code == 0 || it.code == 200) {
                        _state.value = UIState.OnSuccess(it.data, type)
                    } else {
                        if (it.msg == null) {
                            _state.value = UIState.OnFailed(it.message)
                        } else {
                            _state.value = UIState.OnFailed(it.msg)
                        }
                    }
                }
        }
    }

    //下载的方法
    fun download(url: String, file: File) {
        viewModelScope.launch {
            DownloadUtils.download(url, file)
                .flowOn(Dispatchers.IO)
                .catch {
                    Log.e("TagA", "下载错误:${it.message}")
                }.collect {
                    _state.value = it
                }
        }
    }

    //扫描本地文件
    //扫描后将所有文件保存在一个集合当中,将集合返回给state中的data
    fun scanFile(file: File) {
        viewModelScope.launch {
            try {
                //遍历文件夹中的文件,形成一个集合
                val files = file.listFiles()

                //创建一个集合,其中的类型是自己封装的本地文件类型
                val list = mutableListOf<LocalFileEntity>()

                //循环添加文件家中所有的文件到集合中
                for (i in files) {
                    list.add(LocalFileEntity(i.name, i.absolutePath))
                }

                //循环添加完毕,给成功的状态赋值
                _state.value = UIState.OnSuccess(list)

            } catch (e: Exception) {
                //扫描失败
                _state.value = UIState.OnFailed(e.message.toString())
            }
        }
    }

    fun roomRequest(request: Flow<Any>, type: StateType = StateType.DEFAULT) {
        viewModelScope.launch {
            request.flowOn(Dispatchers.IO)
                .catch {
                    Log.e("TagA", "数据库错误:${it.message}")
                }.collect {
                    if (it != null) {
                        _state.value = UIState.OnSuccess(it, type)
                    } else {
                        _state.value = UIState.OnFailed("数据库查询错误,数据为空")
                    }
                }
        }
    }
}

//封装本地文件实体类,包含文件名和文件路径
data class LocalFileEntity(val fileName: String, val filePath: String)